<script>
import ButtonList from '@/components/ButtonList'
import Tree from '@/components/WrapTree'
import FormPanel from '@/components/FormPanel'
import store from './store'
import { commonMixin } from '@/mixins/common'
import { deepClone } from '@/utils/index'

export default {
  mixins: [store, commonMixin],
  data() {
    return {
      labelWidth: '80px',
      tree: {
        width: '280',
        accordion: false,
        treeMenuButtonList: [
          {
            label: '新增',
            methods: 'handleMenuAdd',
            url: '',
            icon: 'el-icon-circle-plus-outline',
            type: 'text',
            action: 'plus'
          },
          {
            label: '刷新',
            methods: 'refresh',
            url: '',
            icon: 'el-icon-refresh',
            type: 'text'
          },
          {
            label: '展开',
            methods: 'expand',
            url: '',
            icon: 'el-icon-rank',
            type: 'text'
          },
          {
            label: '折叠',
            methods: 'fold',
            url: '',
            icon: 'el-icon-arrow-up',
            type: 'text'
          }
        ],
        treeOperateButtonList: [
          { type: 'text', url: '', icon: 'el-icon-plus', action: 'plus' },
          { type: 'text', url: '', icon: 'el-icon-delete', action: 'delete' }
        ],
        isShowHeader: true,
        showCheckbox: false,
        // iconSetting: function(node) {
        //   if (node.level === 1) {
        //     return {
        //       icon: 'el-icon-document'
        //     }
        //   } else {
        //     return {
        //       svgIcon: 'folder'
        //     }
        //   }
        // },
        search: {
          // searchKey: 'nodeName'
        },
        selectTree: {
          // treeParams: {
          //   get: {
          //     url: "/v1/sys/function/findNextChildNodeTree",
          //     nextNodeKey: "node",
          //     idKey: "id"
          //   }
          // },
          // valueToLabelParams: {
          //   url: '/v1/dataProvider/getFunName',
          //   idKey: 'funId'
          // },
          // clearable: true,
          // lazyCache: false
        },
        nextNodeKey: 'node',
        idKey: 'funId',
        title: '功能树',
        getNextChildNode: this.getNextNode,
        delNode: this.delNode
      },

      pidKey: 'pid',
      idKey: 'funId',
      labelKey: 'funName',
      nodeIdKey: 'id',
      nodeLabelKey: 'text',
      nodeCheckedKey: 'checked',
      nodeChildrenKey: 'children',
      nodeLeafKey: 'leaf',

      currentNode: null,
      dialogType: '',

      formPanel: {
        add: {
          model: {
            funId: '',
            funName: '',
            location: '',
            pid: '',
            orderNo: '',
            funType: '',
            logFlag: 1,
            icon: '',
            version: ''
          },
          fields: [
            {
              label: '功能编号',
              prop: 'funId',
              placeholder: '长度在 3 到 5 个字符',
              anchor: 24,
              ref: 'funId',
              focus: true
            },
            {
              label: '功能名称',
              prop: 'funName',
              placeholder: '输入功能名称',
              anchor: 24
            },
            {
              label: '连接地址',
              prop: 'location',
              placeholder: '输入连接地址',
              anchor: 24
            },
            {
              label: '父功能',
              prop: 'pid',
              placeholder: '请选择父功能',
              xType: 'SelectTree.SYS_FUN',
              anchor: 24
            },
            {
              label: '排序号',
              prop: 'orderNo',
              placeholder: '输入排序号',
              anchor: 24
            },
            {
              label: '功能类型',
              prop: 'funType',
              placeholder: '请选择功能类型',
              xType: 'SelectCode.FUN_TYPE',
              anchor: 24
            },
            {
              label: '记日志',
              prop: 'logFlag',
              xType: 'switch',
              anchor: 24,
              'active-value': 1,
              'inactive-value': 0
            },
            { label: '图标', prop: 'icon', anchor: 24 },
            { label: '版本', prop: 'version', anchor: 24 }
          ],
          rules: {
            funId: [
              { required: true, message: '请输入功能编号', trigger: 'blur' }
            ],
            funName: [
              { required: true, message: '请输入功能名称', trigger: 'blur' }
            ],
            funType: [
              { required: true, message: '请选择功能类型', trigger: 'blur' }
            ]
          },
          title: '新增节点',
          type: 'ADD',
          ref: 'addForm',
          submitBtnList: [
            {
              label: '保存',
              methods: 'handleFormAdd',
              icon: 'el-icon-circle-check-outline',
              type: 'primary',
              disabled: false
            }
          ]
        },
        edit: {
          model: {
            funId: '',
            funName: '',
            location: '',
            pid: null,
            orderNo: '',
            funType: '',
            logFlag: '',
            icon: '',
            version: ''
          },
          fields: [
            {
              label: '功能编号',
              prop: 'funId',
              placeholder: '长度在 3 到 5 个字符',
              anchor: 24,
              disabled: true
            },
            {
              label: '功能名称',
              prop: 'funName',
              placeholder: '输入功能名称',
              anchor: 24,
              focus: true
            },
            {
              label: '连接地址',
              prop: 'location',
              placeholder: '输入连接地址',
              anchor: 24
            },
            {
              label: '父功能',
              prop: 'pid',
              placeholder: '请选择父功能',
              xType: 'SelectTree.SYS_FUN',
              anchor: 24
            },
            {
              label: '排序号',
              prop: 'orderNo',
              placeholder: '输入排序号',
              anchor: 24
            },
            {
              label: '功能类型',
              prop: 'funType',
              placeholder: '请选择功能类型',
              xType: 'SelectCode.FUN_TYPE',
              anchor: 24
            },
            {
              label: '记日志',
              prop: 'logFlag',
              xType: 'switch',
              anchor: 24,
              'active-value': 1,
              'inactive-value': 0
            },
            { label: '图标', prop: 'icon', anchor: 24 },
            { label: '版本', prop: 'version', anchor: 24 }
          ],
          rules: {
            funId: [
              { required: true, message: '请输入功能编号', trigger: 'blur' }
            ],
            funName: [
              { required: true, message: '请输入功能名称', trigger: 'blur' }
            ],
            funType: [
              { required: true, message: '请选择功能类型', trigger: 'blur' }
            ]
          },
          title: '编辑节点',
          type: 'EDIT',
          ref: 'editForm',
          submitBtnList: [
            {
              label: '保存',
              methods: 'handleFormEdit',
              icon: 'el-icon-circle-check-outline',
              type: 'primary',
              disabled: false
            }
          ]
        }
      }
    }
  },
  methods: {
    /**
     * 响应页面左侧 tree 组件派发的 tree-import 事件回调
     *  - 当点击 tree 组件的 导入按钮，tree 组件会派发 tree-import 事件
     * */
    handleTreeImport() {},
    /**
     * 响应页面左侧 tree 组件派发的 tree-subSelect 事件回调
     *  - 当 tree 组件包含下拉树 SelectTree 组件时，SelectTree 组件下拉选择会将下拉选择值通过 tree-subSelect 事件派发出去
     *
     * handleTreeSubSelect(val) {
     *   // val 为 SelectTree 组件派发出来的选择的值
     *   // todo...
     * }
     */
    handleTreeSubSelect() {},
    /**
     * 响应页面左侧 tree 组件派发的 tree-empty 事件回调
     *  - 当 tree 组件数据为空会派发 tree-empty 事件
     *  - 模板中该方法会将页面右侧表单隐藏
     */
    handleTreeEmpty() {
      // this.$refs.editForm && this.$refs.editForm.resetFields()
      this.dialogType = ''
    },
    /**
     * 用户可自定义点击左侧树节点并拿到树节点信息，渲染右侧编辑表单后操作
     */
    renderTreeCheckCallback() {},
    /**
     * 用户可自定义在页面右侧新增表单中对 树节点信息 新增请求成功后操作
     */
    renderAddLocalTreeCallback() {},
    /**
     * 用户可自定义在页面右侧编辑表单中对 树节点信息 编辑请求成功后操作
     */
    renderEditLocalTreeCallback() {},
    /**
     * 用户可自定义在页面左侧 树节点删除 成功后操作
     */
    renderDelLocalTreeCallback() {},
    /**
     * 响应页面左侧 tree 组件派发的 add-treeNode 事件回调
     *  - 当点击 tree 组件 顶部新增按钮 / 树节点的 + 按钮，会派发 add-treeNode 事件 (树节点新增操作)
     *  - 模板中该方法会执行：
     *    -- 页面右侧切换为 树节点信息新增表单面板
     *    -- 将 树节点信息新增表单 的内容置为初始值
     *    -- 若是点击 顶部新增按钮，如果 树节点信息新增表单绑定数据 model 中有上级数据字段（如 pid），则将其值置空；
     *       若是点击 树节点的 + 按钮，如果 树节点信息新增表单绑定数据 model 中有上级数据字段（如 pid），则将当前点击树节点的 唯一标识（如 id）的值赋给新增节点的上级数据字段；
     */
    handleNodeAdd(node) {
      this.dialogType = this.formPanel.add.type
      Object.assign(this.formPanel.add.model, this.initialAddModel)
      if (node) {
        this.currentNode = node
        this.formPanel.add.model[this.pidKey] = node.data[this.nodeIdKey]
      } else {
        this.formPanel.add.model[this.pidKey] = ''
      }
    },
    /**
     * 响应页面左侧 tree 组件派发的 check-treeNode 事件回调
     *  - 当点击 tree 组件的 树节点, 会派发 check-treeNode 事件 (树节点编辑操作)
     *  - 模板中该方法会执行：
     *    -- 将点击的树节点设置为 currentNode
     *    -- 页面右侧切换为 树节点信息编辑表单面板
     *    -- 根据点击的树节点的 唯一标识（如 id）向后台请求该树节点数据：
     *       ---- 清空 树节点信息编辑表单
     *       ---- 使用请求到的数据 覆写 树节点信息编辑表单绑定数据 model
     *       ---- 执行 renderTreeCheckCallback(), 用户可自定义点击左侧树节点并拿到树节点信息，渲染右侧编辑表单后操作
     */
    handleNodeEdit(node) {
      console.log('mixins-tree:::::')
      node && (this.currentNode = node)
      this.dialogType = this.formPanel.edit.type
      const params = {}
      params[this.idKey] = node.data[this.nodeIdKey]
      return this.getNodeInfo(params)
        .then(({ success, message, data }) => {
          if (success) {
            this.$refs.editForm && this.$refs.editForm.resetFields()
            Object.keys(this.formPanel.edit.model).forEach(key => {
              this.$set(this.formPanel.edit.model, key, '')
            })
            for (const key in this.formPanel.edit.model) {
              this.$set(this.formPanel.edit.model, key, data[key])
            }
            this.renderTreeCheckCallback()
            return data
          } else {
            this.$message({
              type: 'error',
              message
            })
            throw new Error(message)
          }
        })
        .catch(err => {
          console.log(err)
          // return Promise.reject(err)
        })
    },
    /**
     * 响应页面左侧 tree 组件派发的 del-treeNode 事件回调
     *  - 当点击 tree 组件的 树节点的删除按钮, 会派发 del-treeNode 事件 (树节点删除操作)
     *  - 模板中该方法会执行：
     *    -- 执行 handleNodeEdit(node)，对 派发出来的 树节点 node 进行编辑操作
     *    -- 执行 renderDelLocalTreeCallback(node)，用户可自定义在页面左侧 树节点删除 成功后操作
     */
    handleNodeDel(node) {
      this.handleNodeEdit(node)
      this.renderDelLocalTreeCallback(node)
    },
    /**
     * 点击页面右侧 树节点信息新增表单面板 保存按钮 触发
     *  - 模板中该方法会执行：
     *    -- 对 树节点信息新增表单内容 进行验证
     *    -- 验证成功则发送新增请求，发送 树节点信息新增表单绑定数据 model:
     *       ---- 新增请求发送成功，则提示成功信息，执行 addLocalTree(this.formPanel.add.model)，对左侧 tree 本地进行新增树节点操作
     *       ---- 新增请求失败，则提示失败信息
     */
    handleFormAdd() {
      return this.$refs.addForm
        .validate()
        .then(() => {
          return this.addNodeInfo(this.formPanel.add.model)
        })
        .then(({ success, message }) => {
          this.$message({
            type: success ? 'success' : 'error',
            message
          })
          if (success) {
            this.addLocalTree(this.formPanel.add.model)
          } else {
            throw new Error(message)
          }
        })
        .catch(err => {
          console.log(err)
          // return Promise.reject(err)
        })
    },
    /**
     * 点击页面右侧 树节点信息编辑表单面板 保存按钮 触发
     *  - 模板中该方法会执行：
     *    -- 发送编辑请求，发送 树节点信息编辑表单绑定数据 model:
     *       ---- 编辑发送成功，则提示成功信息，执行 editLocalTree(this.formPanel.edit.model)，对左侧 tree 本地进行编辑树节点操作
     *       ---- 编辑失败，则提示失败信息
     */
    handleFormEdit() {
      return this.$refs.editForm
        .validate()
        .then(() => {
          return this.updateNodeInfo(this.formPanel.edit.model)
        })
        .then(({ success, message }) => {
          this.$message({
            type: success ? 'success' : 'error',
            message
          })
          if (success) {
            this.editLocalTree(this.formPanel.edit.model)
          } else {
            throw new Error(message)
          }
        })
        .catch(err => {
          console.log(err)
          // return Promise.reject(err)
        })
    },
    /**
     * 页面右侧 树节点信息 新增请求成功后触发，对左侧 tree 本地进行新增树节点操作
     *  - 模板中该方法会执行：
     *    -- 新增树节点数据没有上级数据字段（如 pid），直接刷新树
     *    -- 若是新增树节点数据有上级数据字段（如 pid）：
     *       ---- 在当前树中查找 父节点，没找到则直接刷新树；
     *            找到就展开该父节点并添加
     *    -- 执行 renderAddLocalTreeCallback(data)，用户可自定义树节点信息 新增请求成功后操作
     */
    addLocalTree(data) {
      // 没有添加父节点，直接刷新树
      if (!data[this.pidKey]) {
        this.$refs.tree.refresh()
      } else {
        // 在当前树中查找父节点
        const pNode = this.$refs.tree.getNodeById(data[this.pidKey])
        if (pNode) {
          // 找到就添加并展开下拉
          this.$refs.tree.handleNodeExpand(pNode.data, true).then(() => {
            // 有可能后端没有这么快能生成对应节点
            if (this.$refs.tree.getNodeById(data[this.IdKey])) {
              const node = this.$refs.tree.getNodeById(data[this.IdKey])
              this.$refs.tree.setCurrentNodeById(data[this.IdKey])
              this.handleNodeEdit(node)
            } else {
              this.currentNode && this.handleNodeEdit(this.currentNode)
              // this.$refs.tree.expand(data[this.idKey])
            }
          })
        } else {
          // 因为分步加载，没找到直接刷新
          this.$refs.tree.refresh()
        }
      }
      this.renderAddLocalTreeCallback(data)
    },
    /**
     * 页面右侧 树节点信息 编辑请求成功后触发，对左侧 tree 本地进行编辑树节点操作
     *  - 模板中该方法会执行：
     *    -- 编辑树节点数据中没有修改父节点：
     *       ---- 节点数据修改了 label，直接通过修改 currentNode 中 data 对应 label 的值
     *       ---- 传入 currentNode 执行 handleNodeEdit(this.currentNode)，切换页面右侧为 树节点信息编辑面板
     *    -- 编辑树节点数据中修改了父节点：
     *       ---- 先删除当前树节点，再执行 addLocalTree(data)，找到新的父节点插入
     *    -- 执行 renderEditLocalTreeCallback(data)，用户可自定义树节点信息 编辑请求成功后操作
     */
    editLocalTree(data) {
      // eslint-disable-next-line
      const noPidChange =
        (data[this.pidKey] &&
          this.currentNode.parent.data[this.nodeIdKey] &&
          data[this.pidKey] === this.currentNode.parent.data[this.nodeIdKey]) ||
        (!data[this.pidKey] && this.currentNode.level === 1)
      if (data[this.labelKey] && noPidChange) {
        // 没有修改父节点
        this.currentNode.data[this.nodeLabelKey] = data[this.labelKey]
        this.handleNodeEdit(this.currentNode)
      } else {
        // 修改了父节点
        // 先删除当前节点
        this.$refs.tree.delLocalTree(this.currentNode)
        // 再找到新的父节点插入
        this.addLocalTree(data)
      }
      this.renderEditLocalTreeCallback(data)
    },
    /**
     * 渲染页面左侧 tree 组件 jsx 写法
     */
    // eslint-disable-next-line
    renderTree(h) {
      return (
        <Tree
          ref='tree'
          tree={this.tree}
          nodeIdKey={this.nodeIdKey}
          nodeLabelKey={this.nodeLabelKey}
          nodeCheckedKey={this.nodeCheckedKey}
          nodeChildrenKey={this.nodeChildrenKey}
          nodeLeafKey={this.nodeLeafKey}
          on-add-treeNode={this.handleNodeAdd}
          on-check-treeNode={this.handleNodeEdit}
          on-del-treeNode={this.handleNodeDel}
          on-tree-empty={this.handleTreeEmpty}
          on-tree-subSelect={this.handleTreeSubSelect}
          on-tree-import={this.handleTreeImport}></Tree>
      )
    },
    /**
     * 渲染页面右侧 表单 jsx 写法
     */
    // eslint-disable-next-line
    renderFormPanel(h) {
      return this._l(this.formPanel, item => {
        if (this.dialogType === item.type) {
          return (
            <FormPanel
              key={item.type}
              class='c-form-common'
              ref={item.ref}
              items={item.fields}
              inline={false}
              props-model={item.model}
              labelWidth={this.labelWidth}
              rules={item.rules}>
              <div class='el-form-header' slot='title'>
                {item.title}
              </div>
              <c-form-item class='submit-btn'>
                <ButtonList operateBtnList={item.submitBtnList} />
              </c-form-item>
            </FormPanel>
          )
        }
      })
    },
    /**
     * 渲染页面自定义模板 jsx 写法（这里使用空白节点占位）
     */
    // eslint-disable-next-line
    renderCustom(h) {
      return this._e()
    }
  },
  mounted() {
    this.initialAddModel = deepClone(this.formPanel.add.model)
  },
  render(h) {
    return (
      <div class='two-columns'>
        <div class='left'>{this.renderTree(h)}</div>
        <div class='right treePanel'>{this.renderFormPanel(h)}</div>
        {this.renderCustom(h)}
      </div>
    )
  },
  components: {
    Tree,
    FormPanel,
    ButtonList
  }
}
</script>
<style lang="scss">
.left {
  height: 100%;
  overflow: hidden !important;
}
</style>
